package org.darcy.config;

import java.text.SimpleDateFormat;
import java.util.List;

import org.darcy.config.bean.DateConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
import cn.dev33.satoken.interceptor.SaRouteInterceptor;
import cn.dev33.satoken.strategy.SaStrategy;
import lombok.extern.slf4j.Slf4j;

@Configuration
@Slf4j
public class WebConfig implements WebMvcConfigurer {

	@Value("${upload.path}")
	private String uploadPath;

	/**
	 * 静态资源配置
	 */
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
		registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
		registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
		// 本地上传的文件访问
		registry.addResourceHandler("/file/**").addResourceLocations("file:///" + uploadPath + "/");
	}

	/**
	 * 跨域配置
	 */
	@Override
	public void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/**").allowedMethods("*").allowedOriginPatterns("*").allowedHeaders("*")
				.allowCredentials(true);
	}

	/**
	 * 跨域过滤器
	 */
	@Bean
	public CorsFilter corsFilter() {
		CorsConfiguration corsConfiguration = new CorsConfiguration();
		corsConfiguration.addAllowedOriginPattern("*");
		corsConfiguration.setAllowCredentials(true);
		corsConfiguration.addAllowedHeader("*");
		corsConfiguration.addAllowedMethod("*");

		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
		source.registerCorsConfiguration("/**", corsConfiguration);
		return new CorsFilter(source);
	}

	private String[] excludePath = { "/auth/**", "/file/**", "/error", "/druid/**", "/swagger-resources/**", "/swagger-ui/**",
			"/v3/api-docs/**", "/webjars/**", "/doc.html" };

	/**
	 * 注册Sa-Token 的拦截器，打开注解式鉴权功能
	 */
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 注册注解拦截器
		registry.addInterceptor(new SaAnnotationInterceptor()).excludePathPatterns(excludePath);
		// 注册路由拦截器
		registry.addInterceptor(new SaRouteInterceptor()).excludePathPatterns("/**").excludePathPatterns(excludePath);
	}

	/**
	 * 重写 Sa-Token 框架内部算法策略
	 */
	@Autowired
	public void rewriteSaStrategy() {
		// 重写Sa-Token的注解处理器，增加注解合并功能
		SaStrategy.me.getAnnotation = (element, annotationClass) -> {
			return AnnotatedElementUtils.getMergedAnnotation(element, annotationClass);
		};
	}

	/**
	 * 添加自定义的Converters和Formatters.
	 * 
	 * 前台->后台
	 * 
	 * 支持多种日期形式
	 */
	@Override
	public void addFormatters(FormatterRegistry registry) {
		registry.addConverter(new DateConverter());
	}

	/**
	 * 添加自定义的Converters
	 * 
	 * 后台->前台
	 * 
	 * 日期统一返回的格式为: yyyy-MM-dd HH:mm:ss
	 */
	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		log.info("WebConfig->configureMessageConverters 配置 JSON转换器");
		converters.add(jackson2HttpMessageConverter());
		// super.configureMessageConverters(converters);
	}

	@Bean
	public ObjectMapper objectMapper() {
		ObjectMapper mapper = new ObjectMapper();
		mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
		// mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
		return mapper;
	}

	// 定义时间格式转换器
	@Bean
	public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() {
		MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
		converter.setObjectMapper(objectMapper());
		return converter;
	}

}
